using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace PowerGo.Engine
{
    public class GlobalMouseHook : IDisposable
    {
        // 低级鼠标钩子类型
        private const int WH_MOUSE_LL = 14;

        // 鼠标消息常量（部分常用）
        private const int WM_MOUSEMOVE = 0x0200;         // 鼠标移动
        private const int WM_LBUTTONDOWN = 0x0201;       // 左键按下
        private const int WM_LBUTTONUP = 0x0202;         // 左键释放
        private const int WM_RBUTTONDOWN = 0x0204;       // 右键按下
        private const int WM_RBUTTONUP = 0x0205;         // 右键释放
        private const int WM_MBUTTONDOWN = 0x0207;       // 中键按下
        private const int WM_MBUTTONUP = 0x0208;         // 中键释放
        private const int WM_MOUSEWHEEL = 0x020A;        // 鼠标滚轮（垂直）
        private const int WM_MOUSEHWHEEL = 0x020E;       // 鼠标滚轮（水平，如横向滚动）

        // 钩子句柄
        private IntPtr _hookHandle = IntPtr.Zero;
        // 钩子回调函数委托（必须保持引用，防止GC回收）
        private LowLevelMouseProc _hookProc;

        // 鼠标钩子回调函数委托定义
        private delegate IntPtr LowLevelMouseProc(
            int nCode, IntPtr wParam, IntPtr lParam);

        // Windows API导入
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(
            int idHook, LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(
            IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        // 鼠标事件参数类（扩展信息）
        public class MouseEventArgs : EventArgs
        {
            public int X { get; }          // 鼠标X坐标（屏幕坐标）
            public int Y { get; }          // 鼠标Y坐标（屏幕坐标）
            public MouseButtons Button { get; } // 触发事件的按键
            public int WheelDelta { get; } // 滚轮滚动值（正值向前，负值向后）
            public bool Handled { get; set; } // 是否阻止事件传递给其他程序

            public MouseEventArgs(int x, int y, MouseButtons button, int wheelDelta = 0)
            {
                X = x;
                Y = y;
                Button = button;
                WheelDelta = wheelDelta;
            }
        }

        // 事件定义
        public event EventHandler<MouseEventArgs> MouseMove;
        public event EventHandler<MouseEventArgs> MouseDown;
        public event EventHandler<MouseEventArgs> MouseUp;
        public event EventHandler<MouseEventArgs> MouseWheel;

        // 构造函数
        public GlobalMouseHook()
        {
            _hookProc = HookCallback; // 保存委托引用，防止被GC回收
        }

        // 启动钩子
        public void Start()
        {
            if (_hookHandle != IntPtr.Zero)
                return;

            // 获取当前进程主模块句柄
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                _hookHandle = SetWindowsHookEx(
                    WH_MOUSE_LL,
                    _hookProc,
                    GetModuleHandle(curModule.ModuleName),
                    0); // 0表示全局钩子（所有线程）
            }

            if (_hookHandle == IntPtr.Zero)
            {
                throw new System.ComponentModel.Win32Exception();
            }
        }

        // 停止钩子
        public void Stop()
        {
            if (_hookHandle != IntPtr.Zero)
            {
                UnhookWindowsHookEx(_hookHandle);
                _hookHandle = IntPtr.Zero;
            }
        }

        // 钩子回调函数（处理鼠标事件）
        private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0) // nCode >= 0 表示需要处理事件
            {
                // 解析鼠标信息（lParam指向MSLLHOOKSTRUCT结构体）
                MSLLHOOKSTRUCT hookStruct = Marshal.PtrToStructure<MSLLHOOKSTRUCT>(lParam);
                MouseButtons button = MouseButtons.None;
                int wheelDelta = 0;
                bool isWheelEvent = false;

                // 根据消息类型判断事件
                switch ((int)wParam)
                {
                    case WM_MOUSEMOVE:
                        MouseMove?.Invoke(this, new MouseEventArgs(
                            hookStruct.pt.x, hookStruct.pt.y, button));
                        break;

                    case WM_LBUTTONDOWN:
                    case WM_LBUTTONUP:
                        button = MouseButtons.Left;
                        break;

                    case WM_RBUTTONDOWN:
                    case WM_RBUTTONUP:
                        button = MouseButtons.Right;
                        break;

                    case WM_MBUTTONDOWN:
                    case WM_MBUTTONUP:
                        button = MouseButtons.Middle;
                        break;

                    case WM_MOUSEWHEEL:
                        // 滚轮值：高16位为滚动量（WHEEL_DELTA=120）
                        wheelDelta = (short)((hookStruct.mouseData >> 16) & 0xffff);
                        isWheelEvent = true;
                        break;

                    case WM_MOUSEHWHEEL:
                        // 水平滚轮（部分鼠标支持）
                        wheelDelta = (short)((hookStruct.mouseData >> 16) & 0xffff);
                        isWheelEvent = true;
                        break;
                }

                // 触发鼠标按下/释放事件
                if (button != MouseButtons.None)
                {
                    var args = new MouseEventArgs(hookStruct.pt.x, hookStruct.pt.y, button);
                    if ((int)wParam == WM_LBUTTONDOWN ||
                        (int)wParam == WM_RBUTTONDOWN ||
                        (int)wParam == WM_MBUTTONDOWN)
                    {
                        MouseDown?.Invoke(this, args);
                    }
                    else
                    {
                        MouseUp?.Invoke(this, args);
                    }
                    // 如果需要阻止事件传递，设置Handled=true
                    if (args.Handled)
                        return (IntPtr)1;
                }

                // 触发滚轮事件
                if (isWheelEvent)
                {
                    var wheelArgs = new MouseEventArgs(
                        hookStruct.pt.x, hookStruct.pt.y, button, wheelDelta);
                    MouseWheel?.Invoke(this, wheelArgs);
                    if (wheelArgs.Handled)
                        return (IntPtr)1;
                }
            }

            // 传递事件到下一个钩子
            return CallNextHookEx(_hookHandle, nCode, wParam, lParam);
        }

        // 鼠标钩子结构体（MSLLHOOKSTRUCT）
        [StructLayout(LayoutKind.Sequential)]
        private struct MSLLHOOKSTRUCT
        {
            public POINT pt;           // 鼠标坐标（屏幕坐标）
            public int mouseData;      // 鼠标数据（如滚轮值）
            public int flags;          // 标志位
            public int time;           // 事件时间戳
            public IntPtr dwExtraInfo; // 额外信息
        }

        // 坐标结构体
        [StructLayout(LayoutKind.Sequential)]
        private struct POINT
        {
            public int x;
            public int y;
        }

        // 释放资源
        public void Dispose()
        {
            Stop();
        }
    }
}
